-- 增加缓存
local addCache = function (cacheData)
    local dataJson = cjson.decode(cacheData);
    local data = dataJson["data"];
    local tableNameKey = dataJson["tableNameKey"];
    local primaryKeyValue = dataJson["primaryKeyValue"];
    local bitMapKey = dataJson["mateDataBitMapKey"];
    local indexTable = dataJson["indexMap"];
    local mateDataVersionKey = dataJson["mateDataVersionKey"];
    local mateDataVersionValue = dataJson["mateDataVersionValue"];
    local mateDataIndexMap = dataJson["mateDataIndexMap"];
    local mateDataMaxIdKey = dataJson["mateDataMaxIdKey"];

    local oldMaxId;
    local oldVersion;
    local resultV = 1;

    local exectuRedis = function ()
        if(redis.call("hexists", tableNameKey, primaryKeyValue) == 1)
        then
            resultV = 2;
            return;
        end;

        -- 基本数据
        redis.call("hset", tableNameKey, primaryKeyValue, cjson.encode(data));
        redis.call("setbit", bitMapKey, primaryKeyValue, 1);

        -- 记录最大的那个id
        oldMaxId = redis.call("get", mateDataMaxIdKey);

        -- 不存在 或 新增值大于当前 redis 中的值
        if(type(oldMaxId) == 'boolean' or (type(oldMaxId) == 'string' and tonumber(oldMaxId) < primaryKeyValue))
        then
            redis.call("set", mateDataMaxIdKey, primaryKeyValue);
        end;

        redis.call("set", mateDataVersionKey, mateDataVersionValue);

        -- 索引数据
        for key, value in pairs(indexTable) do
            redis.call("sadd", key, typeConvert(value));
        end;

        -- 元数据索引
        for key, value in pairs(mateDataIndexMap) do
            redis.call("sadd", key, typeConvert(value));
        end;

        resultV = 0;
    end;


    --[[
        回滚.
        假如有 10 条命令，执行到第 5 条因为某些原因失败了。
        那么会执行回删，将此次的所有写操作撤回

        回滚时候可能存在的情况
        1. 回滚出现错误(此条数据为脏数据)，那么此时应该交由客户端去记录做补偿处理
        2. 在集群环境下如果出现极端情况, 如：A机器执行增加成功, 命令传播给 B 机器执行 lua，
            但是 B 机器执行失败。B机器应该回滚，此时为脏数据，但是为无法捕捉到。此类型的错误
            为 Redis 中不可控因素，无法处理。
    --]]
    local rollback = function ()
        -- 清理此次相关所有信息
        redis.call("hdel", tableNameKey, primaryKeyValue);
        redis.call("setbit", bitMapKey, primaryKeyValue, 0);

        if(oldVersion ~= 'nil')
        then
            redis.call("set", mateDataVersionKey, oldVersion);
        end;

        if(oldMaxId ~= 'nil')
        then
            redis.call("set", mateDataMaxIdKey, oldMaxId);
        end;

        for key, value in pairs(indexTable) do
            redis.call("srem", key, typeConvert(value));
        end;

        for key, value in pairs(mateDataIndexMap) do
            redis.call("srem", key, typeConvert(value));
        end;
    end;

    local rollbackHandler = function ( err )
        xpcall(
            function()
               redis.log(redis.LOG_NOTICE, commandId, "addCacheData >>> script error info: ", err)
               redis.log(redis.LOG_NOTICE, commandId, "addCacheData >>> try rollback, table:", tableNameKey, ", primaryKey", primaryKeyValue)
               rollback();
               redis.log(redis.LOG_NOTICE, commandId, "addCacheData >>> success rollback")
               resultV = 4;
            end,
            function(rollErr)
                -- 回滚失败写入 redis 日志，手动补偿的解决无效数据
                redis.log(redis.LOG_NOTICE, commandId, "addCacheData >>> error rollback, data invalid. table:", tableNameKey, ", primaryKey", primaryKeyValue)
                redis.log(redis.LOG_NOTICE,rollErr);
                resultV = 3;
            end
        );
    end;


    xpcall(exectuRedis, rollbackHandler);

    --0: 执行成功   1:执行失败  2:数据已存在  3:回滚失败 4:执行失败但是回滚成功
    return resultV;
end;



